package org.scau.studentevaluation.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Preconditions;
import org.apache.poi.hssf.usermodel.*;
import org.scau.studentevaluation.client.ActClient;
import org.scau.studentevaluation.client.AttendedStudentListClient;
import org.scau.studentevaluation.client.OtherActClient;
import org.scau.studentevaluation.client.StudentClient;
import org.scau.studentevaluation.entity.ExamAct;
import org.scau.studentevaluation.entity.ExamOtherAct;
import org.scau.studentevaluation.entity.ExamQuery;
import org.scau.studentevaluation.entity.Table;
import org.scau.studentevaluation.entity.bos.ExamBO;
import org.scau.studentevaluation.entity.dos.*;
import org.scau.studentevaluation.entity.enums.*;
import org.scau.studentevaluation.entity.ExamVO;
import org.scau.studentevaluation.entity.response.Result;
import org.scau.studentevaluation.enums.ResponseCodeEnum;
import org.scau.studentevaluation.service.IExamServicePart2;
import org.scau.studentevaluation.service.ImportMapperService;
import org.scau.studentevaluation.util.BeanConvertUtils;
import org.scau.studentevaluation.util.ResultUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: x1aolone
 * @Date: 2020/8/25 14:27
 */
@Service
public class ExamServicePart2Impl implements IExamServicePart2 {

    private final ImportMapperService importMapperService;

    private final StudentClient studentClient;

    private final AttendedStudentListClient attendedStudentListClient;

    private final OtherActClient otherActClient;

    private final ActClient actClient;


    @Autowired
    public ExamServicePart2Impl(ImportMapperService importMapperService, StudentClient studentClient,
                                AttendedStudentListClient attendedStudentListClient, OtherActClient otherActClient,
                                ActClient actClient) {
        this.importMapperService = importMapperService;
        this.studentClient = studentClient;
        this.attendedStudentListClient = attendedStudentListClient;
        this.otherActClient = otherActClient;
        this.actClient = actClient;
    }


    /**
     * 【基本完成】【新增接口未编写】
     * 需要feign调用attendedstudentlist模块中的方法，需要新增!
     * 需要feign调用Act模块中的获取Act方法
     * @param college
     * @return
     */
    @Override
    public List<ExamAct> getActList(String college){
        List <ExamAct> list = new ArrayList<>();
        List<Long> actsList = ResultUtil.checkCodeAndGet(attendedStudentListClient.getActIds(college));
        Set<Long> actsSet = new HashSet<>(actsList);

        for (Long i : actsSet){
            ActDO actDO = ResultUtil.checkCodeAndGet(actClient.getActById(i));
            ExamAct act = new ExamAct();
            BeanUtils.copyProperties(actDO, act);
            act.setActId(actDO.getId()); // lyl 加的，疑似BUG，id与actId字段名不同所以没有赋值到
            if (actDO.getIsPassed() != null) {
                act.setPassed(actDO.getIsPassed().equals(IsPassedEnum.IS_PASSED_TRUE.getType()));
            }
            if (act != null){
                long actId = act.getActId();//获取 actID
                // 获取审核信息
                LambdaQueryWrapper<ExamDO> query = Wrappers.<ExamDO>lambdaQuery()
                        .eq(ExamDO::getActId, actId)
                        .last(" limit 1");
                ExamDO temp = importMapperService.examMapper.selectOne(query);
                if (temp == null){
                    // 未创建审核信息
                    ExamDO insertDO = new ExamDO();
                    insertDO.setActId(actId)
                            .setIsPassed(IsPassedEnum.IS_PASSED_FALSE.getType())
                            .setIsExamed(IsExamedEnum.IS_EXAMED_FALSE.getType())
                            .setIsAppealed(IsAppealedEnum.IS_APPEALED_FALSE.getType())
                            .setCollege(college)
                            .setIsDeleted(IsDeletedEnum.IS_DELETED_FALSE.getType());
                    importMapperService.examMapper.insert(insertDO);
                    act.setPassed(false);
                    act.setExamed(false);
                    act.setAppealed(false);
                    act.setCollege(college);
                    act.setDeleted(false);
                }
                else {
                    boolean passed = temp.getIsPassed().equals(IsDeletedEnum.IS_DELETED_TRUE.getType());
                    boolean examed = temp.getIsExamed().equals(IsExamedEnum.IS_EXAMED_TRUE.getType());
                    boolean appealed = temp.getIsAppealed().equals(IsAppealedEnum.IS_APPEALED_TRUE.getType());
                    boolean deleted = temp.getIsDeleted().equals(IsDeletedEnum.IS_DELETED_TRUE.getType());
                    act.setPassed(passed);
                    act.setExamed(examed);
                    act.setAppealed(appealed);
                    act.setDeleted(deleted);
                    act.setCollege(temp.getCollege());
                    act.setReluIndex(temp.getRuleIndex());
                    act.setSubject(temp.getSubject());
                    act.setReluYear(temp.getRuleYear());
                    act.setMark(temp.getMark());
                    act.setAppealContent(temp.getAppealContent());
                    act.setAppealReply(temp.getAppealReply());
                }
                list.add(act);
            }
        }
        return list;
    }

    /**
     * 【基本完成】
     * 需要feign调用otheract模块中的获取其他活动方法
     * @param college
     * @return
     */
    @Override
    public List<ExamOtherAct> getOtherActList(String college){
        List<OtherActDO> otherActDOList = ResultUtil.checkCodeAndGet(otherActClient.getOtherAct(college));
        List<ExamOtherAct> examOtherActList = otherActDOList.stream().map(otherActDO -> {
            ExamOtherAct e = new ExamOtherAct();
            e.setOtherActDO(otherActDO);
            return e;
        }).collect(Collectors.toList());
        for (ExamOtherAct act : examOtherActList){
            long oacId = act.getOtherActDO().getId();
            LambdaQueryWrapper<ExamDO> query = Wrappers.<ExamDO>lambdaQuery()
                    .eq(ExamDO::getOtherActId, oacId)
                    .last(" limit 1");
            ExamDO temp = importMapperService.examMapper.selectOne(query);
            if (temp == null){
                ExamDO insertDO = new ExamDO();
                insertDO.setOtherActId(oacId)
                        .setIsPassed(IsPassedEnum.IS_PASSED_FALSE.getType())
                        .setIsExamed(IsExamedEnum.IS_EXAMED_FALSE.getType())
                        .setIsAppealed(IsAppealedEnum.IS_APPEALED_FALSE.getType())
                        .setCollege(college)
                        .setAppealContent("")
                        .setAppealReply("")
                        .setIsDeleted(IsDeletedEnum.IS_DELETED_FALSE.getType());
                importMapperService.examMapper.insert(insertDO);
            }
            else {
                //赋值
                boolean deleted = temp.getIsDeleted().equals(IsDeletedEnum.IS_DELETED_TRUE.getType());
                act.setRuleIndex(temp.getRuleIndex());
                act.setSubject(temp.getSubject());
                act.setRuleYear(temp.getRuleYear());
                act.setMark(temp.getMark());
                act.setAppealReply(temp.getAppealReply());
                act.setDeleted(deleted);
            }
        }
        return examOtherActList;
    }


    @Override
    public int examedNum(String college){
        List<ExamAct> acts = getActList(college);
        List<ExamOtherAct> otherActs = getOtherActList(college);
        int count = 0;
        for (ExamAct act : acts) {
            if (act.isExamed()) {
                count++;
            }
        }
        for (ExamOtherAct act : otherActs) {
            if (act.getOtherActDO().getIsChecked()
                    .equals(IsCheckedEnum.IS_CHECKED_TRUE.getType())) {
                count++;
            }
        }
        return count;
    }


    /**
     * 【勉强完成】【新增接口未编写】
     * student表里面还有一个number（学号）字段？
     * 需要feign调用student模块中的获取学生信息方法【勉强完成】
     * 通过feign调用AttendedStudentList模块中获取学生的活动Id的方法
     * 通过feign调用other_act模块中获取学生的其他活动Id的方法
     *
     * 【新增】通过feign调用otheract模块的方法，通过otherActivityId和otherActivityYear获取数据
     * @param college
     * @return
     */
    public List<Table> getTable(String college){
        //获取该学院的年度总表
        //1、查表获得所有学生学号、姓名
        //2、根据学号查表获得其所有的活动
        //3、计算出该学生的 德育总分，智育总分、体育总分，总分，然后降序排列
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        if (calendar.get(Calendar.MONTH)<10) {
            year--;
        }
        List<StudentDO> studentDOS = ResultUtil.checkCodeAndGet(studentClient.getStudentInfo(college));
        List<Table> tables = studentDOS.stream().map(x -> {
            Table t = new Table();
            BeanUtils.copyProperties(x, t);
            return t;
        }).collect(Collectors.toList());
        for (Table table: tables){
            //根据学号查找所有的加分
            long number = table.getNumber();//学号
            float de = 0;
            float zhi = 0;
            float ti = 0;
            float sum = 0;
            List<Long> actIds = ResultUtil.checkCodeAndGet(attendedStudentListClient.getActIds(number));
            List<Long> oacIds = ResultUtil.checkCodeAndGet(otherActClient.getOtherActivityIds(number));
            for (Long i : actIds){
                LambdaQueryWrapper<ExamDO> query = Wrappers.<ExamDO>lambdaQuery()
                        .eq(ExamDO::getRuleYear, year)
                        .eq(ExamDO::getActId, i)
                        .last(" limit 1");
                ExamDO exam = importMapperService.examMapper.selectOne(query);
                if (exam!=null){//查找到当年的活动
                    int subject = exam.getSubject();
                    int reluIndex = exam.getRuleIndex();
                    float mark = exam.getMark();
                    boolean isPasses = exam.getIsPassed().equals(IsPassedEnum.IS_PASSED_TRUE.getType());
                    if (isPasses){
                        if (subject == 0) {
                            de += mark;
                        }
                        else if (subject == 1) {
                            zhi += mark;
                        }
                        else if (subject == 2) {
                            ti += mark;
                        }
                    }
                }
            }
            for (Long i : oacIds){
                //根据oacId 获取
                LambdaQueryWrapper<ExamDO> query = Wrappers.<ExamDO>lambdaQuery()
                        .eq(ExamDO::getRuleYear, year)
                        .eq(ExamDO::getOtherActId, i)
                        .last(" limit 1");
                ExamDO exam = importMapperService.examMapper.selectOne(query);

                Integer isChecked = ResultUtil.checkCodeAndGet(otherActClient.getIsChecked(i));
                boolean pass = IsCheckedEnum.IS_CHECKED_TRUE.getType().equals(isChecked);

                if (pass && exam!=null){
                    int subject = exam.getSubject();
                    int reluIndex = exam.getRuleIndex();
                    float mark = exam.getMark();
                    boolean isPasses = exam.getIsPassed().equals(IsPassedEnum.IS_PASSED_TRUE.getType());
                    if (isPasses){
                        if (subject == 0) {
                            de += mark;
                        }
                        else if (subject == 1) {
                            zhi += mark;
                        }
                        else if (subject == 2) {
                            ti += mark;
                        }
                    }
                }
            }
            sum = de + zhi + ti;
            table.setDe(de);
            table.setZhi(zhi);
            table.setTi(ti);
            table.setSum(sum);
        }
        // 冒泡排序
        for (int i = 0; i< tables.size()-1;i++){
            for(int j = 0;j< tables.size()-i-1;j++){
                if (tables.get(j).getSum() < tables.get(j+1).getSum()){
                    Table temp = tables.get(j);
                    tables.set(j,tables.get(j+1));
                    tables.set(j+1,temp);
                }
            }
        }
        return tables;
    }

    @Override
    public HSSFWorkbook getWorkbook (String college) {
        //获取排序好的结果
        List<Table> tables = getTable(college);

        //表头数据
        String[] header = {"学号", "姓名", "德育分", "智育分", "体育分", "总分"};

        //声明一个工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();

        //生成一个表格，设置表格名称为"学生表"
        HSSFSheet sheet = workbook.createSheet("综测年度结果");

        //设置表格列宽度为10个字节
        sheet.setDefaultColumnWidth(10);

        //创建第一行表头
        HSSFRow headrow = sheet.createRow(0);

        //遍历添加表头(下面模拟遍历学生，也是同样的操作过程)
        for (int i = 0; i < header.length; i++) {
            //创建一个单元格
            HSSFCell cell = headrow.createCell(i);

            //创建一个内容对象
            HSSFRichTextString text = new HSSFRichTextString(header[i]);

            //将内容对象的文字内容写入到单元格中
            cell.setCellValue(text);
        }

        //模拟遍历结果集，把内容加入表格
        //模拟遍历第一个学生
        for (int i = 1;i<=tables.size();i++){
            //一行行的添加数据
            HSSFRow row = sheet.createRow(i); //创建行
            long number = tables.get(i-1).getNumber();
            String name =  tables.get(i-1).getName();
            float sum = tables.get(i-1).getSum();
            float de = tables.get(i-1).getDe();
            float zhi = tables.get(i-1).getZhi();
            float ti = tables.get(i-1).getTi();

            HSSFCell cell = row.createCell(0);
            HSSFRichTextString text = new HSSFRichTextString(String.valueOf(number));
            cell.setCellValue(text);

            cell = row.createCell(1);
            text = new HSSFRichTextString(String.valueOf(name));
            cell.setCellValue(text);

            cell = row.createCell(2);
            text = new HSSFRichTextString(String.valueOf(de));
            cell.setCellValue(text);

            cell = row.createCell(3);
            text = new HSSFRichTextString(String.valueOf(zhi));
            cell.setCellValue(text);

            cell = row.createCell(4);
            text = new HSSFRichTextString(String.valueOf(ti));
            cell.setCellValue(text);

            cell = row.createCell(5);
            text = new HSSFRichTextString(String.valueOf(sum));
            cell.setCellValue(text);
        }

        return workbook;

    }

    @Override
    public List<ExamVO> listExamByOtherActId(Long otherActId) {
        Preconditions.checkNotNull(otherActId, "otherActId不能为空");
//        List<ExamDO> DOs = null;
        // 目前有空指针问题，解决后需要测试下面两个问题
        // 测试存入提取是否有问题
        // 测试key存在但不是List时，会出什么问题
//        System.err.println(redisTemplate);
//        String redisKey = "exam:listExamByOtherActId:otherActId:" + otherActId;
//        if (redisUtil.isExistKey(redisKey)) {
//            DOs = redisUtil.getList(redisKey);
//            System.err.println("redis中已经有，值为" + DOs.toString());
//        }
//        if (DOs != null) {
//            System.err.println("redis中没有，从数据库中拿");
//            LambdaQueryWrapper<ExamDO> query = Wrappers.<ExamDO>lambdaQuery()
//                    .eq(ExamDO::getOtherActId, otherActId);
//            DOs = importMapperService.examMapper.selectList(query);
//            redisUtil.leftPushAllToList(redisKey, DOs);
//        }
        LambdaQueryWrapper<ExamDO> query = Wrappers.<ExamDO>lambdaQuery()
                    .eq(ExamDO::getOtherActId, otherActId);
        List<ExamDO> DOs = importMapperService.examMapper.selectList(query);
        List<ExamBO> BOs = BeanConvertUtils.DOs2BOs(DOs, ExamBO.class);
        List<ExamVO> VOs = BeanConvertUtils.BOs2VOs(BOs, ExamVO.class);
        return VOs;
    }

    @Override
    public List<ExamVO> listExamByActId(Long actId) {
        LambdaQueryWrapper<ExamDO> query = Wrappers.<ExamDO>lambdaQuery()
                .eq(ExamDO::getActId, actId);
        List<ExamDO> DOs = importMapperService.examMapper.selectList(query);
        List<ExamBO> BOs = BeanConvertUtils.DOs2BOs(DOs, ExamBO.class);
        List<ExamVO> VOs = BeanConvertUtils.BOs2VOs(BOs, ExamVO.class);
        return VOs;
    }

    @Override
    public List<Long> listActId(ExamQuery q) {
        LambdaQueryWrapper<ExamDO> query = Wrappers.<ExamDO>lambdaQuery()
                .eq(ExamDO::getCollege, q.getCollege())
                .eq(ExamDO::getRuleYear, q.getRuleYear())
                .eq(ExamDO::getIsPassed, q.getIsPassed());
        List<ExamDO> DOs = importMapperService.examMapper.selectList(query);
        List<Long> actIds = new ArrayList<>();
        DOs.forEach(x -> {
            if (x.getActId() != null) {
                actIds.add(x.getActId());
            }
        });
        return actIds;

    }

}
